package com.misty.blog.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.misty.blog.bean.param.blog.*;
import com.misty.blog.bean.param.tag.TagSaveParam;
import com.misty.blog.config.PropertyConfig;
import com.misty.blog.service.BlogService;
import com.misty.common.bean.Result;
import com.misty.dao.domain.Blog;
import com.misty.dao.dto.BlogDto;
import com.misty.dao.mapper.BlogMapper;
import com.misty.dao.vo.BlogTagVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author cthulhu
 * @since 2022-11-21
 */
@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements BlogService {

    @Resource
    private BlogMapper blogMapper;


    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private PropertyConfig propertyConfig;


    /**
     *
     * @Param
     * @return
     * @Description 保存博客
     * @Date
     **/
    @Override
    public int saveBlog(Blog blog) {
        blog.setCreateTime(LocalDateTime.now());
        blog.setUpdateTime(LocalDateTime.now());
        return blogMapper.insert(blog);
    }

    /**
     *
     * @Param
     * @return
     * @Description  查询对应博客和用户
     * @Date
     **/
    @Override
    public Result<?> selectByIdWithUser(Integer id){
        QueryWrapper<Blog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("blog.id",id);
        BlogDto blog = blogMapper.selectByIdWithUser(queryWrapper);

        if(ObjectUtil.isEmpty(blog)) {
            return Result.error("查询对应博客和用户失败！");
        }
        return Result.success("查询对应博客和用户成功!",blog);


    }

    /**
     *
     * @Param
     * @return
     * @Description 分页查询博客，可模糊搜索标题
     * @Date
     **/
    @Override
    public Result<?> page(Integer pageNum, Integer pageSize, String search,String tag,String type) {
//        LambdaQueryWrapper<Blog> queryWrapper = Wrappers.<Blog>lambdaQuery();
        QueryWrapper<Blog> queryWrapper = new QueryWrapper<>();
        if(StrUtil.isNotBlank(search)){
            queryWrapper.lambda().like(StrUtil.isNotEmpty(search),Blog::getTitle, search);
        }
        if(StrUtil.isNotEmpty(type)){
            switch (type){
                case "commend":
                    queryWrapper.lambda().orderByDesc(Blog::getLikesCount);
                    break;
                case "new":
                    queryWrapper.lambda().orderByDesc(Blog::getCreateTime);
                    break;
                case "hot":
                    queryWrapper.lambda().orderByDesc(Blog::getViews);
                    break;
                default:
                    break;
            }
        }

        if(StrUtil.isNotEmpty(tag) && !tag.equals("综合")){
            queryWrapper.eq("tag.name",tag);
        }

        Page<BlogDto> blogPage =  blogMapper.selectPageWithUser(new Page<>(pageNum, pageSize), queryWrapper);
        if(blogPage.getTotal() <= 0) {
            return Result.error("分页查询博客失败！");
        }
        queryWrapper.groupBy("blog.id");
        return Result.success("分页查询博客成功!",blogPage);
    }

    /**
     *
     * @Param
     * @return
     * @Description 按阅读量排行查询博客，可模糊搜索标题
     * @Date
     **/
    @Override
    public Result<?> order(Integer pageNum, Integer pageSize, String search) {
        QueryWrapper<Blog> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByAsc("views")
                .like(StrUtil.isNotBlank(search),"title",search);
        Page<BlogDto> blogPage =  blogMapper.selectByOrder(new Page<>(pageNum, pageSize), queryWrapper);
        if(blogPage.getTotal() <= 0) {
            return Result.error("排行查询博客失败！");
        }
        return Result.success("排行查询博客成功!",blogPage);
    }


    /**
     *
     * @Param
     * @return
     * @Description 根据该用户所有博客
     * @Date
     **/
    @Override
    public List<Blog> selectAllByUserId(Integer userId){
        QueryWrapper<Blog> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("blog.user_id",userId);
        return blogMapper.selectAllByUserId(queryWrapper1);
    }


    /**
     *
     * @Param
     * @return
     * @Description 根据该用户分页获取博客
     * @Date
     **/
    @Override
    public Result<Page<Blog>> selectPageByUserId(Integer pageNum, Integer pageSize, Integer userId){
        QueryWrapper<Blog> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("blog.user_id",userId);
        Page<Blog> listPage = blogMapper.selectAllByUserId(new Page<>(pageNum, pageSize), queryWrapper1);
        if(listPage.getTotal()  <= 0){
            return Result.error("根据该用户分页获取博客失败!");
        }
        return Result.success("根据该用户分页获取博客成功!",listPage);
    }

    /**
     *
     * @Param
     * @return
     * @Description 根据该用户所有博客以及标签
     * @Date
     **/
    @Override
    public Result<Page<BlogTagVo>> selectBlogAndTagByUser(BATParam param) {
        Page<BlogTagVo> blogTagVoPage = blogMapper.selectBlogAndTagByUser(
                new Page<>(param.getPageNum(), param.getPageSize())
                , param.getUserId(), param.getTagName()
        );
        if(blogTagVoPage.getTotal() <= 0){
            return Result.error("根据该用户所有博客以及标签失败");
        }
        return Result.success("根据该用户所有博客以及标签成功!",blogTagVoPage);
    }

    /**
     *
     * @Param
     * @return
     * @Description 搜索，获取抓取建议
     * @Date
     **/
    @Override
    public Result<?> fetchSuggest(FetchSuggestParam param) {
        //查询对应搜索排行前十的博客
        QueryWrapper<Blog> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().like(Blog::getTitle,param.getSearch())
                .orderByDesc(Blog::getViews);
        Page<Blog> blogPage = blogMapper
                .selectPage(new Page<>(param.getPageNum(), param.getPageSize()), queryWrapper);
        if(blogPage.getTotal() <= 0){
            return Result.error("获取建议失败!");
        }

        //暂时把标题作为建议，只返回标题列表
        List<Blog> records = blogPage.getRecords();
//        FetchSuggestVo fetchSuggestVo = new FetchSuggestVo();
        List<String> suggestList = records.stream()
                .map((record -> record.getTitle()))
                .collect(Collectors.toList());

        return Result.success("获取建议成功!",suggestList);
    }

    /**
     *
     * @Param
     * @return
     * @Description 点赞
     * @Date
     **/
    @Override
    public Result<?> likeCountChange(LikeCountParam param, Integer currentUserId) {

        //如果当前用户点赞的是自己的博客，则不点赞
        if(judgeIfCurUser(param.getUserId(),currentUserId)){
            return Result.error("不能点赞自己的博客！");
        }

        //更新对应博客的点赞数
        Blog blog = new Blog();
        blog.setId(param.getBlogId())
            .setLikesCount(param.getCount());
        int update = blogMapper.updateById(blog);
        if(update <= 0){
            return Result.error("点赞失败！");
        }
        return Result.success("点赞成功！");
    }

    /**
     *
     * @Param
     * @return
     * @Description 收藏
     * @Date
     **/
    @Override
    public Result<?> colCountChange(ColCountParam param,Integer currentUserId) {

        //如果当前用户收藏的是自己的博客，则不收藏
        if(judgeIfCurUser(param.getUserId(),currentUserId)){
            return Result.error("不能收藏自己的博客！");
        }
        //收藏++
        Blog blog = new Blog();
        blog.setId(param.getBlogId())
                .setCollectionCount(param.getCount());
        int update = blogMapper.updateById(blog);
        if(update <= 0){
            return Result.error("收藏失败！");
        }
        return Result.success("收藏成功！");
    }

    /**
     *
     * @Param
     * @return
     * @Description 判断是否是当前用户的博客
     * @Date
     **/
    private boolean judgeIfCurUser(Integer userId,Integer currentUserId){
        //如果当前用户收藏的是自己的博客，则不收藏
        if(userId.equals(currentUserId)){
            return true;
        }
        return false;
    }

     /**
      * @param
      * @return
      * @Description  编辑博客
      * @Date 2022/12/11 22:53
      */
    @Override
    @Transactional(transactionManager = "mistyTransactionManager")
    public Result updateBlog(SaveParam param, HttpServletRequest request){
        Blog blog = new Blog();
        BeanUtil.copyProperties(param,blog);
        blog.setUpdateTime(LocalDateTime.now());
        int updateById = blogMapper.updateById(blog);
        if(updateById <= 0){
            return Result.error("编辑失败！");
        }

        String url = "http://" + propertyConfig.getIp() + ":" + propertyConfig.getPort() +  "/fore/tag/save";
        TagSaveParam body  = new TagSaveParam();
        body .setBlogId(param.getId())
                .setTagList(param.getTagList());

        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        headers.add("token", request.getHeader("token"));
        //若返回结果是泛型类型的，需要使用到exchange方法，
        //这个方法中有个参数是ParameterizedTypeReference类型，通过这个参数类指定泛型类型
        RequestEntity requestEntity = new RequestEntity(body, headers, HttpMethod.POST, URI.create(url));
        ResponseEntity<Result<String>> responseEntity =
                restTemplate.exchange(
                        requestEntity,
                        new ParameterizedTypeReference<Result<String>>() {
                        }
                );

        Result<String> result = responseEntity.getBody();
        if(result.isErrorResult()){
            return Result.error("编辑失败！");
        }
        return Result.success("编辑成功!");
    }

}
